/*
* Sun Public License Notice
*
* The contents of this file are subject to the Sun Public License
* Version 1.0 (the "License"). You may not use this file except in
* compliance with the License. A copy of the License is available at
* http://www.sun.com/
*
* The Original Code is Forte for Java, Community Edition. The Initial
* Developer of the Original Code is Sun Microsystems, Inc. Portions
* Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved.
*/
package org.netbeans.modules.java;
import java.io.*;
import java.util.*;
import java.beans.PropertyChangeListener;
import javax.swing.text.StyledDocument;
import javax.swing.text.Position;
import sun.tools.java.*;
import sun.tools.javac.*;
import sun.tools.tree.*;
import org.openide.TopManager;
import org.openide.src.*;
import org.openide.text.NbDocument;
import org.openide.text.PositionRef;
import org.openide.text.PositionBounds;
import org.openide.filesystems.FileObject;
import org.openide.loaders.DataObject;
import org.openide.loaders.DataObjectNotFoundException;
import org.openide.util.io.NullOutputStream;
/** Parser of Java source code. It generates the hierarchy
* of the implementations of elements.
*
* @author Petr Hamernik
*/
class JavaParser extends BatchParser {
// ===================== Fields ==============================
/** Mask which contains all possible modifiers used in the hierarchy.
* It filters internal modifiers used in parser.
*/
private static final int MODIF_MASK = M_PUBLIC | M_PRIVATE | M_PROTECTED |
M_STATIC | M_FINAL | M_SYNCHRONIZED | M_VOLATILE | M_TRANSIENT |
M_NATIVE | M_ABSTRACT;
/** JavaDataObject for which source is this parser created. */
JavaDataObject jdo;
/** Appropriate the java editor - used for creating the PositionRefs */
JavaEditor editor;
/** The environment for recognizing the errors after parsing. */
BatchEnvironment environment;
/** Source element implementation */
SourceElementImpl sourceElementImpl;
/** Parsed data. It is created and set to source element impl after
* parsing finish. If this class is null, the parser doesn't collect
* the parsed information.
*/
ParsingResult result;
/** Stack of the classes (ParsingResult.Class)
* @associates Class*/
Stack classesStack;
/** Stack of the begin positions for the members (Long)
* @associates Long*/
Stack memberPositionsStack;
/** The map of the javadoc comments.
* The keys are javadoc strings and the Range classes of javadoc.
* @associates Range
*/
HashMap javadocMap;
/** The position of the begin of last occured expression. */
long lastExpressionBegin;
/** The position of the end of last occured expression. */
long lastExpressionEnd;
/** Marks that there is header parsed. */
boolean headerMark = false;
/** position of last header */
long headerEndPosition;
/** Input stream */
Util.ParserInputStream input;
/** Counter of errors which occurs during resolving fully qualified
* names in parser. If all error occur only during resolving,
* the parser looks like that trere is no error.
*/
int errorsInResolving;
/** Reference to the runnable which has started the parser.
* It is used in SourceElementImpl.setParsingResult after parser finish.
@deprecated SourceElementImpl now uses V8-style parser with different binding.
SourceElementImpl.ParsingRunnable parsingRunnable;
*/
// ===================== Main methods and constructors ==================
/** Constructor directly for parsing without compiler.
* @param fo FileObject where the Java code is stored.
* @exception IOException if any i/o problem occured during reading
*/
public JavaParser(FileObject fo) throws IOException {
this(JavaCompiler.createEnvironment(null), fo);
}
/** Constructor directly for parsing without compiler.
* @param fo FileObject where the Java code is stored.
* @env environment created by Compiler, which is set to 'environment' field
* @exception IOException if any i/o problem occured during reading
*/
private JavaParser(Environment env, FileObject fo) throws IOException {
this(new Environment(env, new CoronaClassFile(fo)), fo, true);
if (env instanceof BatchEnvironment) {
// errors checking - for partially parsed files
this.environment = (BatchEnvironment) env;
}
}
/** Constructor for compiler.
* @param environment The environment passed by the compiler or
* @param fo FileObject where the Java code is stored.
* @param store if there is required the building and storing the elements
* hierarchy
* @exception IOException if any i/o problem occured during reading
*/
public JavaParser(Environment environment, FileObject fo, boolean store) throws IOException {
this(environment, fo, store, createInputStream(fo, store));
}
/** Private constructor.
* @param environment The environment passed by the compiler or
* @param fo FileObject where the Java code is stored.
* @param store if there is required the building and storing the elements
* hierarchy
* @param input the input stream where to read.
* @exception IOException if any i/o problem occured during reading
*/
private JavaParser(Environment environment, FileObject fo, boolean store, Util.ParserInputStream input) throws IOException {
super(environment, input);
this.input = input;
if (!store)
return;
if (environment instanceof BatchEnvironment) {
// errors checking - for partially parsed files
this.environment = (BatchEnvironment) environment;
}
try {
jdo = (JavaDataObject) DataObject.find(fo);
editor = jdo.getJavaEditor();
sourceElementImpl = jdo.getSourceElementImpl();
result = new ParsingResult();
errorsInResolving = 0;
classesStack = new Stack();
memberPositionsStack = new Stack();
if (javadocMap == null)
javadocMap = new HashMap();
}
catch (ClassCastException e) {
TopManager.getDefault().notifyException(e);
}
catch (DataObjectNotFoundException e) {
TopManager.getDefault().notifyException(e);
}
}
/** Creates new input stream from the file object.
* Finds the java data object, checks if the document is loaded and
* and create the stream either from the file object either from the document.
* @param fo fileobject with the source
* @param store if there is required the building and storing the elements
* hierarchy
* @exception IOException if any i/o problem occured during reading
*/
private static Util.ParserInputStream createInputStream(FileObject fo, boolean store) throws IOException {
return (Util.ParserInputStream)Util.createInputStream(fo, false, true);
}
/** Sets the runnable which has started the parser.
* @param parsingRunnable The reference for the runnable which will be
* passed to the SourceElementImpl.setParsingResult after parser finish.
void setParsingRunnable(SourceElementImpl.ParsingRunnable parsingRunnable) {
this.parsingRunnable = parsingRunnable;
}
*/
/** Parses the file - this method starts the parser.
* After super.parseFile finish, the result is set to
* the appropriate SourceElementImpl.
*/
public void parseFile() {
super.parseFile();
if (result != null) {
boolean errors = (environment != null) && (environment.nerrors > errorsInResolving);
if (result.packageId == null)
result.packageBounds = createBiasBounds(0, 0); // begin of the file
/*
Disabled: sourceElementImpl now uses new V8 parser.
sourceElementImpl.setParsingResult(result, errors, parsingRunnable);
*/
}
closeInput();
}
/** This method closes the input stream for parsing, which is always opened
* in the constructor. Method parseFile calls this method, but if anyone just creates
* the JavaParser class, is also responsible for closing the stream.
* Otherwise the stream is closed during finalization.
*/
public void closeInput() {
try {
if (input != null) {
input.close();
input = null;
}
}
catch (IOException e) {
}
}
/** Finalize the parser and close the input stream if necessary.
*/
public void finalize() throws Throwable {
super.finalize();
closeInput();
}
/** Method for the environment - accessibility */
protected Vector getClassesProtected() {
return classes;
}
/** Method for the environment - accessibility */
protected Imports getImportsProtected() {
return imports;
}
// ======================== PARSER METHODS ===============================
// ----------------------- utilities -----------------------------------
/** Computes the real offset from the long value representing position
* in the parser.
* @return the offset
*/
static int position(long p) {
return (int)(p & 0xFFFFFFFFL);
}
/** Creates position bounds. For obtaining the real offsets is used
* previous method position()
* @param begin The begin in the internal position form.
* @param end The end in the internal position form.
* @return the bounds
*/
PositionBounds createBiasBounds(long begin, long end) {
PositionRef posBegin = editor.createPositionRef(position(begin), Position.Bias.Forward);
PositionRef posEnd = editor.createPositionRef(position(end), Position.Bias.Backward);
return new PositionBounds(posBegin, posEnd);
}
/** Converts the object to the full qualified identifier string.
* @param id As the id is passed either sun.tools.java.Identifier either
* IdentifierToken.
* @return fully qualified identifier as a string
*/
String getFullName(Object id) {
sun.tools.java.Identifier ii = (id instanceof IdentifierToken) ?
((IdentifierToken)id).getName() :
(sun.tools.java.Identifier) id;
try {
String ret = env.resolve(ii).toString();
return ret;
}
catch (ClassNotFound e) {
return ii.toString();
}
}
/** Converts the object to the src.Identifier (using toString method)
* @param id As the id is passed either sun.tools.java.Identifier either
* IdentifierToken. Both these classes has well implemented
* toString method.
* @param resolve If identifier should be resolved (fully qualified)
* @return identifier
*/
org.openide.src.Identifier createId(Object id, boolean resolve) {
org.openide.src.Identifier retValue = null;
if (resolve) {
if (environment != null) {
int prev = environment.nerrors;
retValue = org.openide.src.Identifier.create(getIdResolver(id), id.toString());
errorsInResolving += environment.nerrors - prev;
}
else {
retValue = org.openide.src.Identifier.create(getIdResolver(id), id.toString());
}
}
else {
retValue = org.openide.src.Identifier.create(id.toString());
}
return retValue;
}
/** Create new resolver for the identifier.
* @param id As the id is passed either sun.tools.java.Identifier either
* IdentifierToken. Both these classes has well implemented
* toString method.
*/
org.openide.src.Identifier.Resolver getIdResolver(Object id) {
return new EnvironmentalResolver(env, sourceClass, id);
}
/** Resolver implementation - for lazy computing fully
* qualified identifiers.
*/
static class EnvironmentalResolver implements org.openide.src.Identifier.Resolver {
Environment et;
ClassDefinition cd;
Object id;
/** Creates new resolver */
EnvironmentalResolver(Environment e, ClassDefinition cd, Object id) {
this.et = e;
this.id = id;
this.cd = cd;
}
/** Resolve full name */
public String resolve() {
sun.tools.java.Identifier ii = (id instanceof IdentifierToken) ?
((IdentifierToken)id).getName() : (sun.tools.java.Identifier) id;
if (cd.isInnerClass())
ii = cd.getOuterClass().resolveName(et, ii);
else
ii = et.resolveName(ii);
String ret = ii.toString();
// remove space from e.g. 'org.openide.NotifyDescriptor. Exception'
int space = ret.indexOf(' ');
if (space != -1)
ret = ret.substring(0, space) + ret.substring(space + 1);
return ret;
}
}
/** Converts sun.tools.java.Type to org.openide.src.Type
* May be called only for primitive types, class type and array type.
* @param resolve If identifier should be resolved (fully qualified)
*/
org.openide.src.Type typeToType(sun.tools.java.Type type, boolean resolve) {
switch (type.getTypeCode()) {
case TC_BOOLEAN: return org.openide.src.Type.BOOLEAN;
case TC_BYTE: return org.openide.src.Type.BYTE;
case TC_CHAR: return org.openide.src.Type.CHAR;
case TC_SHORT: return org.openide.src.Type.SHORT;
case TC_INT: return org.openide.src.Type.INT;
case TC_LONG: return org.openide.src.Type.LONG;
case TC_FLOAT: return org.openide.src.Type.FLOAT;
case TC_DOUBLE: return org.openide.src.Type.DOUBLE;
case TC_VOID: return org.openide.src.Type.VOID;
case TC_ARRAY: return org.openide.src.Type.createArray(typeToType(((ArrayType) type).getElementType(), resolve));
case TC_CLASS: return org.openide.src.Type.createClass(createId(((ClassType) type).getClassName(), resolve));
case TC_NULL:
case TC_METHOD:
case TC_ERROR:
default:
throw new InternalError();
}
}
/** Object which hold the range in the source stream */
private class Range {
/** begin */
int begin;
/** end */
int end;
/** Constructs new range */
Range(long begin, long end) {
this.begin = position(begin);
this.end = position(end);
}
/** Get the javadoc inside the range as the PositionBounds
* Could be called only when result != null
*/
PositionBounds getCommentBounds() {
String doc = input.getString(begin, end);
//PENDING: not finished - must be improved
long p1 = begin + doc.indexOf("/**");
long p2 = end - doc.length() + doc.lastIndexOf("*/") + 2; // NOI18N
return createBiasBounds(p1, p2);
}
}
/** Get the position bounds for given javadoc.
* The javadoc must be in the table, otherwise NullPointerException is thrown
* @return the position bounds.
*/
private PositionBounds getJavaDocBounds(String doc) {
return ((Range)javadocMap.get(doc)).getCommentBounds();
}
// ----------------- overriden methods -----------------------------------
/** Package declaration */
public void packageDeclaration(long l, IdentifierToken identifiertoken) {
if (result != null) {
result.packageId = createId(identifiertoken, false);
result.packageBounds = createBiasBounds(l, prevPos);
}
super.packageDeclaration(l, identifiertoken);
}
/** Import class declaration */
public void importClass(long l, IdentifierToken identifiertoken) {
if (result != null)
storeImport(l, identifiertoken, Import.CLASS);
super.importClass(l, identifiertoken);
}
/** Import package declaration */
public void importPackage(long l, IdentifierToken identifiertoken) {
if (result != null)
storeImport(l, identifiertoken, Import.PACKAGE);
super.importPackage(l, identifiertoken);
}
/** Stores the given import declaration. */
private void storeImport(long l, IdentifierToken identifiertoken, boolean what) {
result.imports.add(new Import(createId(identifiertoken, false), what));
result.importsBounds.add(createBiasBounds(l, prevPos));
}
/** Parses the class. Only store the current position. */
protected void parseClass() throws SyntaxError, IOException {
if (result != null) {
try {
memberPositionsStack.push(new Long(pos));
headerEndPosition = pos;
headerMark = true;
super.parseClass();
}
finally {
memberPositionsStack.pop();
}
}
else {
super.parseClass();
}
}
/** Scans one token. Calls super class and marks the javadoc comments or
* header ends.
*/
public long scan() throws IOException {
long p1 = pos;
long l = super.scan();
if (result != null) {
if (headerMark) {
if ((token == LBRACE) || (token == SEMICOLON) || (token == ASSIGN)) {
headerEndPosition = prevPos;
headerMark = false;
}
}
}
// comments must be stored, because the first call of this method
// is from <init>
if (docComment != null) {
if (javadocMap == null)
javadocMap = new HashMap();
javadocMap.put(docComment, new Range(p1, pos));
}
return l;
}
/** Parse the expression and store its bounds */
public Expression parseExpression() throws SyntaxError, IOException {
Expression exp = super.parseExpression();
lastExpressionBegin = exp.getWhere();
lastExpressionEnd = pos;
return exp;
}
/** Parses the field. Only store the current position. */
protected void parseField() throws SyntaxError, IOException {
if (result != null) {
try {
memberPositionsStack.push(new Long(pos));
headerEndPosition = pos;
headerMark = true;
super.parseField();
}
finally {
memberPositionsStack.pop();
}
}
else {
super.parseField();
}
}
/** Define one field (method, field, constructor, intializer) */
public void defineField(long where, ClassDefinition c,
String doc, int mod, sun.tools.java.Type t,
IdentifierToken name, IdentifierToken[] args,
IdentifierToken[] exp, Node val) {
super.defineField(where, c, doc, mod, t, name, args, exp, val);
if (result == null)
return;
if ((sourceClass.getModifiers() & M_ANONYMOUS) != 0) {
// skip elements of anonymous inner class
return;
}
ParsingResult.Class declaringClass = (ParsingResult.Class) classesStack.peek();
ElementImpl elementImpl;
if (t.getTypeCode() == Constants.TC_METHOD) {
if (name.getName().equals(Constants.idClassInit)) {
// Initializer
InitializerElementImpl impl = new InitializerElementImpl();
elementImpl = impl;
impl.stat = ((mod & M_STATIC) != 0);
impl.javadoc = new JavaDocImpl(doc, impl);
declaringClass.initializers.add(impl);
}
else {
// Constructor & Method
ConstructorElementImpl impl = (name.getName().equals(Constants.idInit)) ?
new ConstructorElementImpl() : new MethodElementImpl();
elementImpl = impl;
impl.mod = mod & MODIF_MASK;
impl.parameters = new MethodParameter[args.length];
sun.tools.java.Type[] methodArguments = ((MethodType) t).getArgumentTypes();
for (int i = 0; i < args.length; i++) {
impl.parameters[i] = new MethodParameter(
args[i].toString(), typeToType(methodArguments[i], true),
((args[i].getModifiers() & M_FINAL) != 0)
);
}
if (exp == null) {
impl.exceptions = new org.openide.src.Identifier[0];
}
else {
impl.exceptions = new org.openide.src.Identifier[exp.length];
for (int i = 0; i < exp.length; i++) {
impl.exceptions[i] = createId(exp[i], true);
}
}
impl.javadoc = new JavaDocImpl.Method(doc, impl);
if (name.getName().equals(Constants.idInit)) {
// Constructor
impl.name = createId(declaringClass.impl.getName().getName(), false);
declaringClass.constructors.add(impl);
}
else {
// Method
((MethodElementImpl)impl).type = typeToType(((MethodType) t).getReturnType(), true);
impl.name = createId(name, false);
declaringClass.methods.add(impl);
}
}
elementImpl.bodyBounds = (val == null) ?
null :
createBiasBounds(val.getWhere() + 1, prevPos - 1);
}
else {
// Field
FieldElementImpl impl = new FieldElementImpl();
elementImpl = impl;
impl.name = createId(name, false);
impl.mod = mod & MODIF_MASK;
impl.type = typeToType(t, true);
impl.initValue = (val == null) ? "" : // NOI18N
input.getString(position(lastExpressionBegin), position(lastExpressionEnd));
impl.javadoc = new JavaDocImpl.Field(doc, impl);
declaringClass.fields.add(impl);
impl.bodyBounds = (val == null) ?
null :
createBiasBounds(val.getWhere(), prevPos);
}
long beginField = ((Long) memberPositionsStack.peek()).longValue();
long endField = prevPos;
if (elementImpl instanceof FieldElementImpl) {
String tmp = input.getString(position(prevPos));
int firstColon = tmp.indexOf(";"); // NOI18N
endField += firstColon + 1;
}
if (doc == null) { // field without javadoc comment
elementImpl.docBounds = null;
elementImpl.bounds = createBiasBounds(beginField, endField);
}
else { // field with javadoc comment
elementImpl.docBounds = getJavaDocBounds(doc);
long docBeginPosition = elementImpl.docBounds.getBegin().getOffset();
elementImpl.bounds = createBiasBounds(docBeginPosition, endField);
}
elementImpl.headerBounds = createBiasBounds(beginField, headerEndPosition);
headerMark = false;
}
/** Begin of the class */
public ClassDefinition beginClass(long where, String doc, int mod, IdentifierToken t,
IdentifierToken sup, IdentifierToken[] interfaces) {
ClassDefinition clazz = super.beginClass(where, doc, mod, t, sup, interfaces);
if (result == null)
return clazz;
if ((mod & M_ANONYMOUS) != 0) //skip anonymous inner class
return clazz;
headerMark = false;
long beginClass = ((Long) memberPositionsStack.peek()).longValue();
ClassElementImpl impl = new ClassElementImpl();
impl.headerBounds = createBiasBounds(beginClass, headerEndPosition);
impl.name = createId(t, true);
impl.mod = mod & MODIF_MASK;
impl.isClass = ((mod & M_INTERFACE) == 0);
impl.superclass = (sup == null) ? null : createId(sup, true);
impl.interfaces = new org.openide.src.Identifier[interfaces.length];
for (int i = 0; i < interfaces.length; i++)
impl.interfaces[i] = createId(interfaces[i], true);
impl.javadoc = new JavaDocImpl.Class(doc, impl);
try {
ParsingResult.Class outerClass = (ParsingResult.Class) classesStack.peek();
ParsingResult.Class thisClass = new ParsingResult.Class(impl);
outerClass.classes.add(thisClass);
classesStack.push(thisClass);
}
catch (EmptyStackException e) {
ParsingResult.Class thisClass = new ParsingResult.Class(impl);
result.classes.add(thisClass);
classesStack.push(thisClass);
}
return clazz;
}
/** End of the class */
public void endClass(long where, ClassDefinition clazz) {
super.endClass(where, clazz);
if (result == null)
return;
if ((clazz.getModifiers() & M_ANONYMOUS) != 0) //skip anonymous inner class
return;
ParsingResult.Class thisClass = (ParsingResult.Class) classesStack.pop();
long beginClass = ((Long) memberPositionsStack.peek()).longValue();
if (clazz.getDocumentation() == null) { // class without javadoc comment
thisClass.impl.docBounds = null;
thisClass.impl.bounds = createBiasBounds(beginClass, where);
}
else { // field with javadoc comment
thisClass.impl.docBounds = getJavaDocBounds(clazz.getDocumentation());
long docBeginPosition = thisClass.impl.docBounds.getBegin().getOffset();
thisClass.impl.bounds = createBiasBounds(docBeginPosition, where);
}
}
// ==================== The parser input stream ==========================
/** The input stream which holds all data which are read in the StringBuffer.
*/
static class ParserInputStream extends InputStream {
/** The underlaying stream. */
private InputStream stream;
/** Whole text */
private String text;
/** The string buffer which collect the data. */
private StringBuffer buffer;
/** This flag determines if there is used the text field or buffer field.
* The constructor set it
*/
private boolean mode;
/** The counter of read chars */
private int counter;
/** Creates the stream from the text. */
ParserInputStream(String text) {
stream = new StringBufferInputStream(text);
this.text = text;
mode = false;
counter = 0;
}
/** Creates the stream from the another stream. */
ParserInputStream(InputStream stream) {
this.stream = stream;
buffer = new StringBuffer();
mode = true;
}
/** Gets the part of the text which was already read.
* @param begin the begin index
* @param end the end index
*/
public String getString(long begin, long end) {
int p1 = position(begin);
int p2 = position(end);
return mode ? buffer.substring(p1, p2) : text.substring(p1, p2);
}
/** Gets the part of the text which was already read.
* End is last position which was already read.
* @param begin the begin index
*/
public String getString(long begin) {
int p1 = position(begin);
if (mode) {
return buffer.substring(p1);
}
else {
int p2 = Math.min(counter - 1, text.length());
return text.substring(p1, p2);
}
}
/** Read one character from the stream. */
public int read() throws IOException {
int x = stream.read();
if (mode && (x != -1))
buffer.append((char)x);
counter++;
return x;
}
/** Closes the stream */
public void close() throws IOException {
stream.close();
}
}
}
/*
* Log:
* 31 src-jtulach1.30 01/12/00 Petr Hamernik i18n: perl script used (
* //NOI18N comments added )
* 30 src-jtulach1.29 11/05/99 Ales Novak #2206
* 29 src-jtulach1.28 11/03/99 Petr Hamernik fixed #3473 and other
* problems with resolving Identifiers
* 28 src-jtulach1.27 10/23/99 Ian Formanek NO SEMANTIC CHANGE - Sun
* Microsystems copyright in file comment
* 27 src-jtulach1.26 10/08/99 Petr Hamernik fixed bug - close input
* stream
* 26 src-jtulach1.25 10/06/99 Petr Hamernik Streams and Readers
* correction.
* 25 src-jtulach1.24 09/10/99 Petr Hamernik comments
* 24 src-jtulach1.23 09/09/99 Petr Hamernik correct closing streams
* after parsing
* 23 src-jtulach1.22 08/18/99 Petr Hamernik fixed bug #2113
* 22 src-jtulach1.21 08/18/99 Petr Hamernik fixed bug #3173
* 21 src-jtulach1.20 07/23/99 Petr Hamernik global parsing listener
* 20 src-jtulach1.19 06/08/99 Ian Formanek ---- Package Change To
* org.openide ----
* 19 src-jtulach1.18 06/02/99 Petr Hamernik connections of java
* sources
* 18 src-jtulach1.17 05/28/99 Ales Novak lazy resolving of
* identifiers
* 17 src-jtulach1.16 05/26/99 Petr Hamernik compilation bug ffixed
* 16 src-jtulach1.15 05/21/99 Petr Hamernik parsing info garbage
* collected too fast - fixed
* 15 src-jtulach1.14 05/15/99 Petr Hamernik Identifiers resolving
* temporary disabled
* 14 src-jtulach1.13 05/14/99 Petr Hamernik parsing errors during
* resolving Identifiers are ignored
* 13 src-jtulach1.12 05/12/99 Petr Hamernik ide.src.Identifier changed
* 12 src-jtulach1.11 05/12/99 Petr Hamernik javadoc parsing bugfix
* 11 src-jtulach1.10 05/11/99 Petr Hamernik emptyStackExecption bug
* fixed
* 10 src-jtulach1.9 05/10/99 Petr Hamernik
* 9 src-jtulach1.8 04/30/99 Petr Hamernik bounds bugfix
* 8 src-jtulach1.7 04/21/99 Petr Hamernik Java module updated
* 7 src-jtulach1.6 04/15/99 Petr Hamernik parser improvements
* 6 src-jtulach1.5 04/14/99 Ian Formanek Fixes problem with
* programmatic usage of imports
* 5 src-jtulach1.4 04/02/99 Petr Hamernik
* 4 src-jtulach1.3 04/01/99 Petr Hamernik
* 3 src-jtulach1.2 03/29/99 Petr Hamernik
* 2 src-jtulach1.1 03/29/99 Petr Hamernik
* 1 src-jtulach1.0 03/28/99 Ales Novak
*
* Log
* 32 Gandalf-post-FCS1.30.1.0 2/24/00 Ian Formanek Post FCS changes
* 31 src-jtulach1.30 1/12/00 Petr Hamernik i18n: perl script used
* ( //NOI18N comments added )
* 30 src-jtulach1.29 11/5/99 Ales Novak #2206
* 29 src-jtulach1.28 11/3/99 Petr Hamernik fixed #3473 and other
* problems with resolving Identifiers
* 28 src-jtulach1.27 10/23/99 Ian Formanek NO SEMANTIC CHANGE -
* Sun Microsystems copyright in file comment
* 27 src-jtulach1.26 10/8/99 Petr Hamernik fixed bug - close input
* stream
* 26 src-jtulach1.25 10/6/99 Petr Hamernik Streams and Readers
* correction.
* 25 src-jtulach1.24 9/10/99 Petr Hamernik comments
* 24 src-jtulach1.23 9/9/99 Petr Hamernik correct closing streams
* after parsing
* 23 src-jtulach1.22 8/18/99 Petr Hamernik fixed bug #2113
* 22 src-jtulach1.21 8/18/99 Petr Hamernik fixed bug #3173
* 21 src-jtulach1.20 7/23/99 Petr Hamernik global parsing listener
* 20 src-jtulach1.19 6/9/99 Ian Formanek ---- Package Change To
* org.openide ----
* 19 src-jtulach1.18 6/2/99 Petr Hamernik connections of java
* sources
* 18 src-jtulach1.17 5/28/99 Ales Novak lazy resolving of
* identifiers
* 17 src-jtulach1.16 5/26/99 Petr Hamernik compilation bug ffixed
* 16 src-jtulach1.15 5/21/99 Petr Hamernik parsing info garbage
* collected too fast - fixed
* 15 src-jtulach1.14 5/15/99 Petr Hamernik Identifiers resolving
* temporary disabled
* 14 src-jtulach1.13 5/14/99 Petr Hamernik parsing errors during
* resolving Identifiers are ignored
* 13 src-jtulach1.12 5/12/99 Petr Hamernik ide.src.Identifier
* changed
* 12 src-jtulach1.11 5/12/99 Petr Hamernik javadoc parsing bugfix
* 11 src-jtulach1.10 5/11/99 Petr Hamernik emptyStackExecption bug
* fixed
* 10 src-jtulach1.9 5/10/99 Petr Hamernik
* 9 src-jtulach1.8 4/30/99 Petr Hamernik bounds bugfix
* 8 src-jtulach1.7 4/21/99 Petr Hamernik Java module updated
* 7 src-jtulach1.6 4/15/99 Petr Hamernik parser improvements
* 6 src-jtulach1.5 4/14/99 Ian Formanek Fixes problem with
* programmatic usage of imports
* 5 src-jtulach1.4 4/2/99 Petr Hamernik
* 4 src-jtulach1.3 4/1/99 Petr Hamernik
* 3 src-jtulach1.2 3/29/99 Petr Hamernik
* 2 src-jtulach1.1 3/29/99 Petr Hamernik
* 1 src-jtulach1.0 3/28/99 Ales Novak
* $
*/